<!DOCTYPE html>
<html lang="zh-cn">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <title>遍历 PCI 设备 - whowin - 发表我个人原创作品的技术博客</title>
  <meta name="renderer" content="webkit" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>

<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />

<meta name="theme-color" content="#f8f5ec" />
<meta name="msapplication-navbutton-color" content="#f8f5ec">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="#f8f5ec">


<meta name="author" content="whowin" /><meta name="description" content="PC机在启动的时候，都会看到一个PCI设备清单，可以看到机器中的所有PCI设备，其实搜索PCI设备的程序并不难编，本文通过一个实例说明如何遍历PCI设备。本文程序的工作环境：MS-DOS 6.22，djgpp&#43;RHIDE。本文初次发表于2008年4月2日，2011年3月11日做过修改，将其中的代码片段换为完整代码。
" /><meta name="keywords" content="linux, socket, hugo, dos" />






<meta name="generator" content="Hugo 0.97.3 with theme even" />


<link rel="canonical" href="https://whowin.gitee.io/post/blog/dos/0005-traverse-pci-devices/" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/manifest.json">
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">



<link href="/sass/main.min.e3fea119b1980e848b03dffbeddb11dd0fba483eed0e5f11870fb8e31f145bbd.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.1.20/dist/jquery.fancybox.min.css" integrity="sha256-7TyXnr2YU040zfSP+rEcz29ggW4j56/ujTPwjMzyqFY=" crossorigin="anonymous">


<meta property="og:title" content="遍历 PCI 设备" />
<meta property="og:description" content="PC机在启动的时候，都会看到一个PCI设备清单，可以看到机器中的所有PCI设备，其实搜索PCI设备的程序并不难编，本文通过一个实例说明如何遍历PCI设备。本文程序的工作环境：MS-DOS 6.22，djgpp&#43;RHIDE。本文初次发表于2008年4月2日，2011年3月11日做过修改，将其中的代码片段换为完整代码。" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://whowin.gitee.io/post/blog/dos/0005-traverse-pci-devices/" /><meta property="article:section" content="post" />
<meta property="article:published_time" content="2008-04-02T09:15:23+08:00" />
<meta property="article:modified_time" content="2008-04-02T09:15:23+08:00" />

<meta itemprop="name" content="遍历 PCI 设备">
<meta itemprop="description" content="PC机在启动的时候，都会看到一个PCI设备清单，可以看到机器中的所有PCI设备，其实搜索PCI设备的程序并不难编，本文通过一个实例说明如何遍历PCI设备。本文程序的工作环境：MS-DOS 6.22，djgpp&#43;RHIDE。本文初次发表于2008年4月2日，2011年3月11日做过修改，将其中的代码片段换为完整代码。"><meta itemprop="datePublished" content="2008-04-02T09:15:23+08:00" />
<meta itemprop="dateModified" content="2008-04-02T09:15:23+08:00" />
<meta itemprop="wordCount" content="2924">
<meta itemprop="keywords" content="DOS,DJGPP,保护模式,RHIDE,PCI," /><meta name="twitter:card" content="summary"/>
<meta name="twitter:title" content="遍历 PCI 设备"/>
<meta name="twitter:description" content="PC机在启动的时候，都会看到一个PCI设备清单，可以看到机器中的所有PCI设备，其实搜索PCI设备的程序并不难编，本文通过一个实例说明如何遍历PCI设备。本文程序的工作环境：MS-DOS 6.22，djgpp&#43;RHIDE。本文初次发表于2008年4月2日，2011年3月11日做过修改，将其中的代码片段换为完整代码。"/>

<!--[if lte IE 9]>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/classlist/1.1.20170427/classList.min.js"></script>
<![endif]-->

<!--[if lt IE 9]>
  <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
<![endif]-->

  <script async src="/js/busuanzi.pure.mini.js"></script><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9724909319263152"
     crossorigin="anonymous"></script>


</head>
<body>
  <div id="mobile-navbar" class="mobile-navbar">
  <div class="mobile-header-logo">
    <a href="/" class="logo">WhoWin</a>
  </div>
  <div class="mobile-navbar-icon">
    <span></span>
    <span></span>
    <span></span>
  </div>
</div>
<nav id="mobile-menu" class="mobile-menu slideout-menu">
  <ul class="mobile-menu-list">
    <a href="/">
        <li class="mobile-menu-item">首页</li>
      </a><a href="/post/">
        <li class="mobile-menu-item">文章归档</li>
      </a><a href="/article-categories/categories/">
        <li class="mobile-menu-item">文章分类</li>
      </a><a href="/tags/">
        <li class="mobile-menu-item">文章标签</li>
      </a><a href="/about/about/">
        <li class="mobile-menu-item">关于</li>
      </a>
  </ul>

  


</nav>

  <div class="container" id="mobile-panel">
    <header id="header" class="header">
        <div class="logo-wrapper">
  <a href="/" class="logo">WhoWin</a>
  
  <div style="position:absolute; left: 80px; top: 75px; color: crimson">
      ———开源和分享是技术发展的源泉和动力；本博客所有文章均为原创
  </div>
</div>





<nav class="site-navbar">
  <ul id="menu" class="menu">
    <li class="menu-item">
        <a class="menu-item-link" href="/">首页</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/post/">文章归档</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/article-categories/categories/">文章分类</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/tags/">文章标签</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/about/about/">关于</a>
      </li>
  </ul>
</nav>

    </header>

    <main id="main" class="main">
      <div class="content-wrapper">
        <div id="content" class="content">
          <article class="post">
    
    <header class="post-header">
      <h1 class="post-title">遍历 PCI 设备</h1>

      <div class="post-meta">
        <span class="post-time"> 2008-04-02 </span>
        <div class="post-category">
            <a href="/categories/dos/"> DOS </a>
            </div>
        
      </div>
    </header>

    <div class="post-toc" id="post-toc">
  <h2 class="post-toc-title">文章目录</h2>
  <div class="post-toc-content always-active">
    <nav id="TableOfContents">
  <ul>
    <li>
      <ul>
        <li><a href="#1了解pci设备">1、了解PCI设备</a></li>
        <li><a href="#2你的-bios-是否支持-pci-bios-服务">2、你的 BIOS 是否支持 PCI BIOS 服务</a></li>
        <li><a href="#3了解pci配置空间">3、了解PCI配置空间</a></li>
        <li><a href="#4配置寄存器的读写">4、配置寄存器的读写</a></li>
        <li><a href="#5遍历pci设备">5、遍历PCI设备</a></li>
      </ul>
    </li>
  </ul>
</nav>
  </div>
</div>
    <div class="post-content">
      <p>PC机在启动的时候，都会看到一个PCI设备清单，可以看到机器中的所有PCI设备，其实搜索PCI设备的程序并不难编，本文通过一个实例说明如何遍历PCI设备。本文程序的工作环境：MS-DOS 6.22，djgpp+RHIDE。本文初次发表于2008年4月2日，2011年3月11日做过修改，将其中的代码片段换为完整代码。</p>
<h2 id="1了解pci设备">1、了解PCI设备</h2>
<blockquote>
<p>PCI的含义是外设部件互连（Peripheral Component Interconnect），PCI局部总线（Local Bus）是1991年由Intel定义的，现在PCI局部总线已经成为了PC机中不可缺少的外围设备总线，几乎所有的外部设备都连接到PCI局部总线上，我们说的PCI设备，实际上就是指连接在PCI局部总线上的设备。</p>
</blockquote>
<h2 id="2你的-bios-是否支持-pci-bios-服务">2、你的 BIOS 是否支持 PCI BIOS 服务</h2>
<blockquote>
<p>在我的另一篇博客文章：<a href="https://whowin.gitee.io/post/blog/dos/0001-32bit-bios-introduction/">《32位BIOS说明》</a>中，说明了如何判断 <strong>BIOS</strong> 是否是32位的，以及是否支持PCI BIOS服务，实际上，并没有那么麻烦，因为在绝大多数有 PCI 插槽的 PC 机中，BIOS 都是32位的，同时也是支持 PCI BIOS 的，在我的另一篇博客文章：<a href="https://whowin.gitee.io/post/blog/dos/0002-invoking-pci-bios/">《调用PCI BIOS》</a>中，介绍了PCI BIOS中常用的功能调用，其中的第一个调用就是检查 <strong>PCI BIOS的存在性</strong>，通常我们利用这个功能调用来作为 PCI BIOS 的存在检测已经足够了，方法如下：</p>
</blockquote>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">  汇编语言：
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      MOV  AX, 0B01H
</span></span><span class="line"><span class="cl">      INT 1AH
</span></span></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">  C语言（DJGPP下）：
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      long unsigned int    i;
</span></span><span class="line"><span class="cl">      __dpmi_regs           r;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      r.x.ax = 0xb101;
</span></span><span class="line"><span class="cl">      __dpmi_int(0x1a, &amp;r);
</span></span><span class="line"><span class="cl">      i = r.x.flags;
</span></span><span class="line"><span class="cl">      if ((i &amp; 0x01) == 0) printf(&#34;\nSupport PCI BIOS&#34;);
</span></span><span class="line"><span class="cl">      else printf(&#34;\nNot Suport PCI BIOS&#34;);
</span></span></code></pre></td></tr></table>
</div>
</div><blockquote>
<p>根据返回参数就可以判断 <strong>PCI BIOS</strong> 是否存在，具体方法请参阅：<a href="https://whowin.gitee.io/post/blog/dos/0002-invoking-pci-bios/">《调用PCI BIOS》</a>这篇博客文章，如果你的BIOS不支持PCI BIOS，那么本文介绍的方法可能不完全适用你。</p>
</blockquote>
<h2 id="3了解pci配置空间">3、了解PCI配置空间</h2>
<ul>
<li>
<p>学习PCI编程，不了解PCI的配置空间是不可能的，配置空间是一块容量为 <strong>256</strong> 字节并具有特定记录结构或模型的地址空间，通过配置空间，我们可以了解该 <strong>PCI</strong> 设备的一些配置情况，进而控制该设备，除主总线桥以外的所有 <strong>PCI</strong> 设备都必须事先配置空间，本节仅就一些配置空间的共有的规定作一些说明，更加具体和详细的信息请参阅其他书籍及相应的芯片手册。</p>
</li>
<li>
<p>配置空间的前 64 个字节叫头标区，头标区又分成两个部分，第一部分为前 16 个字节，在各种类型的设备中定义都是一样的，其他字节随各设备支持的功能不同而有所不同，位于偏移 0EH 的投标类型字段规定了是何种布局，目前有三种头标类型，头标类型 1 用于 PCI-PCI 桥，头标类型 2 用于 PCI-CARDBUS 桥，头标类型 0 用于其他 PCI 设备，下图为头标类型 0 的头标区布局。</p>
<p><img src="https://whowin.gitee.io/images/160005/traverse_PCI_devices_01.jpg" alt="遍历PCI设备"></p>
<p><strong>图1：遍历 PCI 设备</strong></p>
</li>
<li>
<p>头标区中有 5 个字段涉及设备的识别。</p>
<ol>
<li>
<p>供应商识别字段（Vendor ID）</p>
<blockquote>
<p>偏移：00H。该字段用以标明设备的制造者。一个有效的供应商标识由PCI SIG来分配，以保证它的唯一性。0FFFFH是该字段的无效值。</p>
</blockquote>
</li>
<li>
<p>设备识别字段（Device ID）</p>
<blockquote>
<p>偏移：02H。用以标明特定的设备，具体代码由供应商来分配。</p>
</blockquote>
</li>
<li>
<p>版本识别字段（Revision ID）</p>
<blockquote>
<p>偏移：08H。用来指定一个设备特有的版本识别代码，其值由供应商提供，可以是0。</p>
</blockquote>
</li>
<li>
<p>头标类型字段（Header Type）</p>
<blockquote>
<p>偏移：0EH。该字段有两个作用，一是用来表示配置空间头标区第二部分的布局类型；二是用以指定设备是否包含多功能。位7用来标识一个多功能设备，位7为0表明是单功能设备，位7为1表明是多功能设备。位0-位6表明头标区类型。</p>
</blockquote>
</li>
<li>
<p>分类代码字段（Class Code）</p>
<blockquote>
<p>偏移：09H。标识设备的总体功能和特定的寄存器级编程接口。该字节分三部分，每部分占一个字节，第一部分是基本分类代码，位于偏移0BH，第二部分叫子分类代码，位于偏移0AH处，第三部分用于标识一个特定的寄存器级编程接口（如果有的话）。</p>
</blockquote>
</li>
</ol>
</li>
<li>
<p>这部分的代码定义很多，请自行查阅 <strong>PCI规范</strong> 相关文档。我们在实际应用中会对一些用到的代码加以说明。</p>
</li>
</ul>
<h2 id="4配置寄存器的读写">4、配置寄存器的读写</h2>
<ul>
<li>
<p>x86的CPU只有内存和I/O两种空间，没有专用的配置空间，PCI协议规定利用特定的I/O空间操作驱动PCI桥路转换成配置空间的操作。目前存在两种转换机制，即配置机制1#和配置机制2#。配置机制2#在新的设计中将不再被采用，新的设计应使用配置机制1#来产生配置空间的物理操作。这种机制使用了两个特定的32位I/O空间，即CF8h和CFCh。这两个空间对应于PCI桥路的两个寄存器，当桥路看到CPU在局部总线对这两个I/O空间进行双字操作时，就将该I/O操作转变为PCI总线的配置操作。寄存器CF8h用于产生配置空间的地址（CONFIG-ADDRESS），寄存器CFCh用于保存配置空间的读写数据（CONFIG-DATA）。</p>
</li>
<li>
<p>将要访问配置空间寄存器的总线号、设备号、功能号和寄存器号以一个双字的格式写到配置地址端口 (CF8H-CFBH)，接着执行配置数据端口 (CFCH)的读和写，向配置数据口写数据即向配置空间写数据，从配置数据口读数据即从配置空间读数据。</p>
</li>
<li>
<p>配置地址端口（CF8H）的格式定义如下：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">  bit  31  30...24 23......16 15......11 10......8 7..........2   1  0
</span></span><span class="line"><span class="cl">        |    保留     总线号     设备号    功能号      寄存器号     0  0
</span></span><span class="line"><span class="cl">        +----使能位，1有效，0无效
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  寄存器号：选择配置空间中的一个双字（32位）
</span></span><span class="line"><span class="cl">  功能号：选择多功能设备中的某一个功能，有八种功能，0--7
</span></span><span class="line"><span class="cl">  设备号：在一条给定的总线上选择32个设备中的一个。0--31
</span></span><span class="line"><span class="cl">  总线号：从系统中的256条总线中选择一条，0--255
</span></span></code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>尽管理论上可以有 <strong>256</strong> 条总线，但实际上 PC 机上 <em>8PCI</em>* 插槽的总线号都是 <strong>1</strong>，有些工控机的总线号是 2 或者 3，所以我们只需要查找 <strong>0&ndash;4</strong> 号总线就足够了。</p>
</li>
<li>
<p>PCI规范规定，功能 <strong>0</strong> 是必须实现的，所以，如果功能 <strong>0</strong> 的头标类型字段的位 7 为 0，表明这是一个单功能设备，则没有必要再去查其他功能，否则要查询所有其他功能。</p>
</li>
</ul>
<h2 id="5遍历pci设备">5、遍历PCI设备</h2>
<ul>
<li>
<p>至此，我们掌握的有关 PCI 的知识已经足够我们遍历 PCI 设备了，其实便利方法非常简单就是按照总线号、设备号、功能号的顺序依次罗列所有的可能性，读取配置空间头标区的供应商代码、及设备代码，进而找到所有 PCI 设备。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">#include &lt;stdio.h&gt;
</span></span><span class="line"><span class="cl">#include &lt;dpmi.h&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">typedef unsigned long      UDWORD;
</span></span><span class="line"><span class="cl">typedef unsigned short int UWORD;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">int main() {
</span></span><span class="line"><span class="cl">    UDWORD i, busNo, deviceNo, funcNo, regVal, retVal, baseAddr;
</span></span><span class="line"><span class="cl">    UWORD  vendorID, devID, class1, class2, class3;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    __dpmi_regs r;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    r.x.ax = 0xb101;
</span></span><span class="line"><span class="cl">    __dpmi_int(0x1a, &amp;r);
</span></span><span class="line"><span class="cl">    i = r.x.flags;
</span></span><span class="line"><span class="cl">    if ((i &amp; 0x01) == 0) printf(&#34;\nSupport PCI BIOS.&#34;);
</span></span><span class="line"><span class="cl">    else printf(&#34;\nNot Support PCI BIOS.&#34;);
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    printf(&#34;\nNo.  Vendor/Device  Bus No.  Dev No.  Func No.  Class&#34;);
</span></span><span class="line"><span class="cl">    i = 0;
</span></span><span class="line"><span class="cl">    for (busNo = 0; busNo &lt; 5; busNo++) {                      // bus No
</span></span><span class="line"><span class="cl">        for(deviceNo = 0; deviceNo &lt; 32; deviceNo++) {         // device no
</span></span><span class="line"><span class="cl">            for (funcNo = 0; funcNo &lt; 8; funcNo++) {           // Function No
</span></span><span class="line"><span class="cl">                //j = 0x80000000 + i * 2048;
</span></span><span class="line"><span class="cl">                regVal = 0x80000000                            // bit31 使能
</span></span><span class="line"><span class="cl">                        + (busNo &lt;&lt; 16)                        // Bus No
</span></span><span class="line"><span class="cl">                        + (deviceNo &lt;&lt; 11)                     // Device No
</span></span><span class="line"><span class="cl">                        + (funcNo &lt;&lt; 8);                       // Function No
</span></span><span class="line"><span class="cl">                outportl(0xCF8, regVal);
</span></span><span class="line"><span class="cl">                retVal = inportl(0xCFC);                       // 得到配置空间偏移为0的双字
</span></span><span class="line"><span class="cl">                if (retVal != 0xffffffff) {                    // 设备存在
</span></span><span class="line"><span class="cl">                    i++;
</span></span><span class="line"><span class="cl">                    vendorID = retVal &amp; 0xffff;                // 得到供应商代码
</span></span><span class="line"><span class="cl">                    devID    = (retVal &gt;&gt; 16) &amp; 0xffff;        // 得到设备代码
</span></span><span class="line"><span class="cl">                    regVal += 0x08;                            // 得到配置空间偏移为08H的双字
</span></span><span class="line"><span class="cl">                    outportl(0xCF8, regVal);
</span></span><span class="line"><span class="cl">                    retVal = inportl(0xCFC);
</span></span><span class="line"><span class="cl">                    retVal = retVal &gt;&gt; 8;                      // 滤掉版本号
</span></span><span class="line"><span class="cl">                    class3 = retVal &amp; 0x0FF;                   // 得到三个分类代码
</span></span><span class="line"><span class="cl">                    class2 = (retVal &gt;&gt; 8) &amp;0x0FF;
</span></span><span class="line"><span class="cl">                    class1 = (retVal &gt;&gt; 8) &amp;0x0FF;
</span></span><span class="line"><span class="cl">                    printf(&#34;\n%02d   %04x/%04x       %02x       %02x       %02x      %02x-%02x-%02x&#34;,
</span></span><span class="line"><span class="cl">                          i, vendorID, devID, busNo, deviceNo, funcNo, class1, class2, class3);
</span></span><span class="line"><span class="cl">                    if (funcNo == 0) {                         // 如果是单功能设备，则不再查funcNo&gt;0的设备
</span></span><span class="line"><span class="cl">                        regVal = (regVal &amp; 0xFFFFFFF0) + 0x0C; // 配置空间偏移0X0C，
</span></span><span class="line"><span class="cl">                        outportl(0xCF8, regVal);
</span></span><span class="line"><span class="cl">                        retVal = inportl(0xCFC);
</span></span><span class="line"><span class="cl">                        retVal = retVal &gt;&gt; 16;                 // 偏移0X0E为投标类型字段
</span></span><span class="line"><span class="cl">                        if ((retVal &amp; 0x80) == 0) funcNo = 8;  // bit 7为0表示为单功能设备，不再查该设备的其他功能
</span></span><span class="line"><span class="cl">                    }
</span></span><span class="line"><span class="cl">                }
</span></span><span class="line"><span class="cl">            }
</span></span><span class="line"><span class="cl">        }
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">}   // end of main
</span></span></code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>这是一个完整的遍历PCI设备的程序，本代码可以DJGPP下编译通过并正常执行（测试环境：DOS 6.22 DJGPP2.2+RHIDE1.5）。</p>
</li>
</ul>
<hr>
<p><strong>欢迎访问我的博客：https://whowin.cn</strong></p>
<p><strong>email: <a href="mailto:hengch@163.com">hengch@163.com</a></strong></p>
<p><img src="https://whowin.gitee.io/images/qrcode/sponsor-qrcode.png" alt="donation"></p>
    </div>

    <div class="post-copyright">
  <p class="copyright-item">
    <span class="item-title">文章作者</span>
    <span class="item-content">whowin</span>
  </p>
  <p class="copyright-item">
    <span class="item-title">上次更新</span>
    <span class="item-content">
        2008-04-02
        
    </span>
  </p>
  
  
</div>
<footer class="post-footer">
      <div class="post-tags">
          <a href="/tags/dos/">DOS</a>
          <a href="/tags/djgpp/">DJGPP</a>
          <a href="/tags/%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F/">保护模式</a>
          <a href="/tags/rhide/">RHIDE</a>
          <a href="/tags/pci/">PCI</a>
          </div>
      <nav class="post-nav">
        <a class="prev" href="/post/blog/dos/0006-dos-int15h-introduction/">
            <i class="iconfont icon-left"></i>
            <span class="prev-text nav-default">DOS的系统杂项服务INT 15H介绍</span>
            <span class="prev-text nav-mobile">上一篇</span>
          </a>
        <a class="next" href="/post/blog/dos/0004-install-djgpp-rhide-under-dos/">
            <span class="next-text nav-default">在 DOS 下的 DJGPP &#43; RHIDE 安装实作</span>
            <span class="next-text nav-mobile">下一篇</span>
            <i class="iconfont icon-right"></i>
          </a>
      </nav>
    </footer>
  </article>
        </div>
        

  <span id="/post/blog/dos/0005-traverse-pci-devices/" class="leancloud_visitors" data-flag-title="遍历 PCI 设备">
		<span class="post-meta-item-text">文章阅读量 </span>
		<span class="leancloud-visitors-count">0</span>
		<p></p>
	  </span>
  <div id="vcomments"></div>
  <script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
  <script src='//unpkg.com/valine/dist/Valine.min.js'></script>
  <script type="text/javascript">
    new Valine({
        el: '#vcomments' ,
        appId: 'OFCGzCfJRUglzOdzrqMGkbTR-gzGzoHsz',
        appKey: 'v7P29kPAEbsmaavaYPNhGhnF',
        notify:  false ,
        verify:  false ,
        avatar:'mm',
        placeholder: '说点什么吧...',
        visitor:  true 
    });
  </script>

  

      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="social-links">
      <a href="mailto:hengch@163.com" class="iconfont icon-email" title="email"></a>
  <a href="https://whowin.gitee.io/index.xml" type="application/rss+xml" class="iconfont icon-rss" title="rss"></a>
</div>
<div class="copyright">
  <span class="power-by">
    由 <a class="hexo-link" href="https://gohugo.io">Hugo</a> 强力驱动
  </span>
  <span class="division">|</span>
  <span class="theme-info">
    主题 - 
    <a class="theme-link" href="https://github.com/olOwOlo/hugo-theme-even">Even</a>
  </span>

  <div class="busuanzi-footer">
    <span id="busuanzi_container_site_pv"> 本站总访问量 <span id="busuanzi_value_site_pv"><img src="/img/spinner.svg" alt="spinner.svg"/></span> 次 </span>
      <span class="division">|</span>
    <span id="busuanzi_container_site_uv"> 本站总访客数 <span id="busuanzi_value_site_uv"><img src="/img/spinner.svg" alt="spinner.svg"/></span> 人 </span>
  </div>

  <span class="copyright-year">
    &copy; 
    2022 - 
    2024<span class="heart"><i class="iconfont icon-heart"></i></span><span>whowin</span>
  </span>
</div>

    </footer>

    <div class="back-to-top" id="back-to-top">
      <i class="iconfont icon-up"></i>
    </div>
  </div>
  
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/slideout@1.0.1/dist/slideout.min.js" integrity="sha256-t+zJ/g8/KXIJMjSVQdnibt4dlaDxc9zXr/9oNPeWqdg=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.1.20/dist/jquery.fancybox.min.js" integrity="sha256-XVLffZaxoWfGUEbdzuLi7pwaUJv1cecsQJQqGLe7axY=" crossorigin="anonymous"></script>



<script type="text/javascript" src="/js/main.min.64437849d125a2d603b3e71d6de5225d641a32d17168a58106e0b61852079683.js"></script>
  <script type="text/javascript">
    window.MathJax = {
      tex: {
        inlineMath: [['$','$'], ['\\(','\\)']],
        }
    };
  </script>
  <script async src="https://cdn.jsdelivr.net/npm/mathjax@3.0.5/es5/tex-mml-chtml.js" integrity="sha256-HGLuEfFcsUJGhvB8cQ8nr0gai9EucOOaIxFw7qxmd+w=" crossorigin="anonymous"></script>








</body>
</html>
